package com.dayu.finecomm.protocol.hd72;

import java.util.Calendar;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.dayu.finecomm.protocol.codec.Protocol;
import com.dayu.finecomm.protocol.codec.ProtocolDecoder;
import com.dayu.finecomm.protocol.pojo.TPacket;
import com.dayu.finecomm.protocol.pojo.TPacket.VType;
import com.dayu.finecomm.protocol.pojo.TSensor;
import com.dayu.finecomm.utils.Helpers;

import io.netty.buffer.ByteBuf;

@Protocol(XDDDDDecoder.PROTO)
public class XDDDDDecoder extends ProtocolDecoder<TPacket> {

	static final String PROTO = "HD72";
	private static final int P = 0;
	private static final int K = 1;
	private static final int A = 2;
	private static final int Q = 3;
	private static final int M = 4;

	private static final int MAGIC = 0xDDDD;
	static Logger LOGGER = LoggerFactory.getLogger(XDDDDDecoder.class);

	@Override
	public int checkStart(ByteBuf in) {
		return 0;
	}

	@Override
	public int check(ByteBuf in) {

		if (in.readableBytes() < 31)
			return -1;

		// 协议头校验
		int c = in.readUnsignedShort();
		int sn = in.readUnsignedShort(); // 跳过站号
		int length = in.readUnsignedShort();

		if (c != MAGIC) // 协议头
			return -1;

		// 协议尾校验
		ByteBuf b = in.slice(length - 2, 2);
		if (b.readUnsignedShort() != 0x0d0a)
			return -1;

		b = in.slice(0, length - 2);

		// CRC校验
		int crc = 0;

		for (int i = 0; i < length - 3; i++) {
			crc = crc ^ b.readUnsignedByte();
		}

		crc = ~(crc + sn);
		crc = (0xff & crc) ^ b.readUnsignedByte();

		if (crc != 0)
			return -1;

		return length;
	}

	@Override
	public TPacket unpack(ByteBuf in) {

		in.skipBytes(2); // DD DD
		int sn = in.readUnsignedShort();

		int length = in.readUnsignedShort(); // length

		int nYear = 2000 + in.readUnsignedByte();
		int nMonth = in.readUnsignedByte() - 1;
		int nDay = in.readUnsignedByte();
		int nHour = in.readUnsignedByte();
		int nMinute = in.readUnsignedByte();
		int nSecond = in.readUnsignedByte();

		Calendar c = Calendar.getInstance();
		c.set(nYear, nMonth, nDay, nHour, nMinute, nSecond);
		c.set(Calendar.MILLISECOND, 0);

		long sTime = c.getTime().getTime();

		TPacket s = new TPacket(VType.PPP, PROTO, sn, sTime);

		// Reserved
		in.skipBytes(6);

		int nInterval;

		short x = in.readUnsignedByte();

		nInterval = HD72Convention.intervalDDDD(x);
		if (nInterval == 0)
			return null;

		int n = in.readUnsignedByte();

		// Reserved
		in.skipBytes(8);

		for (; in.readerIndex() < length - 3;) {

			int type = in.readUnsignedByte();
			int no = in.readUnsignedByte();

			String channel;

			switch (type) {
			case P:
				in.skipBytes(4);
				channel = "P" + no;
				break;
			case K:
				channel = "K" + no;
				break;
			case A:
				channel = "A" + no;
				break;
			case Q:
				channel = "Q" + no;
				break;
			case M:
				channel = "M" + no;
				break;
			default:
				return null;
			}

			for (int i = 0; i < n; i++) {

				switch (type) {
				case P: // P通道
				{
					int val = in.readInt();
					s.sensors.add(new TSensor(channel, val, sTime + nInterval * i));
				}
					break;
				case K: // K通道
				{
					int val = in.readUnsignedByte();
					s.sensors.add(new TSensor(channel, val, sTime + nInterval * i));
				}
					break;
				case A:// A通道
				{
					float val = Float.intBitsToFloat(Integer.reverseBytes(in.readInt()));
					s.sensors.add(new TSensor(channel, val, sTime + nInterval * i));
				}
					break;
				case Q:// Q通道
				{

					for (int j = 0, k = in.readUnsignedShort(); j < 16; j++, k >>>= 1) {

						int val = k & 1;
						s.sensors.add(new TSensor(channel + "_" + j, val, sTime + nInterval * i));
					}
				}
					break;
				case M: // M通道
				{

					for (int j = 1; j < 5; j++) {

						String k = Helpers.byteToHexString(in.readByte());

						s.sensors.add(
								new TSensor(channel + "_" + (2 * j - 1), k.substring(0, 1), sTime + nInterval * i));
						s.sensors.add(new TSensor(channel + "_" + (2 * j), k.substring(1), sTime + nInterval * i));
					}
				}
					break;
				default:
					return null;
				}
			}
		}

		return s;
	}

	@Override
	public Object timing() {
		return HD72Convention.timing();
	}

	@Override
	public byte[] echo() {
		return "@222".getBytes();
	}
}
